﻿#region

using System.IO;
using System.Reflection;
using MediaSage.Lib.Configuration;
using MediaSage.Lib.Database;
using MediaSage.Lib.Plugin;
using MediaSage.Lib.Utilities;
using Microsoft.VisualStudio.TestTools.UnitTesting;

#endregion

namespace FileNameProviderTests
{
    using System.Collections.Generic;
    using HibernatingRhinos.Profiler.Appender.NHibernate;
    using MediaSage.Lib;

    /// <summary>
    ///     Summary description for UnitTest1
    /// </summary>
    [TestClass]
    public class FileNameProviderTest
    {
        #region Fields

        private static Config config;

        private static PluginBase provider;

        #endregion Fields

        #region Constructors

        [ClassInitialize]
        [DeploymentItem("TMDBProvider.dll")]
        [DeploymentItem("TVDBProvider.dll")]
        public static void LoadConfiguration(TestContext testContext)
        {
            NHibernateProfiler.Initialize();
            config = new Config();
            var installer = new Installer(config);
            string InstallFile = Path.Combine(Directory.GetCurrentDirectory(), "FileNameProvider.zip");
            bool result = installer.InstallPlugin(InstallFile, false);
            Assert.AreEqual(true, result, "Installation failed");
            provider = config.PluginManager.GetPlugin("FileNameProvider");
        }

        #endregion Constructors

        #region Properties

        ///<summary>
        ///    Gets or sets the test context which provides
        ///    information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext { get; set; }

        #endregion Properties

        #region Methods

        [TestMethod]
        public void FilenameProviderGetName()
        {
            VersionInfo vi = provider.GetVersionInfo();
            Assert.AreEqual("FileNameProvider", vi.Name);
        }

        [TestMethod]
        public void FilenameProviderGetVersionTest()
        {
            VersionInfo vi = provider.GetVersionInfo();
            Assert.AreEqual(vi.Name, "FileNameProvider");
            Assert.AreEqual(vi.MajorVersion, 0);
            Assert.AreEqual(vi.MinorVersion, 9);
        }

        [TestMethod]
        public void FilenameProviderLoadTest()
        {
            Assert.AreNotEqual(null, provider, "Failed to load FileNameProvider");
        }

        /// <summary>
        ///     This tests if an installation succeds for a specific video provider, no reinstall
        /// </summary>
        [TestMethod]
        [DeploymentItem("FileNameProvider.zip")]
        [DeploymentItem("IMDBMovies.dat")]
        public void FilenameProviderTestInstaller()
        {
            var installer = new Installer(config);
            string InstallFile = Path.Combine(Directory.GetCurrentDirectory(), "FileNameProvider.zip");
            bool result = installer.InstallPlugin(InstallFile, false);
            Assert.AreEqual(true, result, "Installation failed");

            PluginEntity pe = Plugin.GetConfigurationByName("FileNameProvider");

            // First check to see that our 2 files are there
            CheckFiles(pe);
            Assert.AreEqual(17, pe.ExtensionsHandled.Count,
                            "Expected 17 extensions handled, got: " + pe.ExtensionsHandled.Count);
            Assert.AreEqual(9,pe.ConfigurationItems.Count, 
                            "Expected 9 Configuration Items for plugin, got: " + pe.ConfigurationItems.Count);
        }

        [TestMethod]
        [DeploymentItem("FileNameProvider.zip")]
        public void FileNameProviderTestUninstall()
        {
            var installer = new Installer(config);

            // Check to see if the plugin was installed by a previous test method, if it was uninstall that one
            PluginEntity dPE = Plugin.GetConfigurationByName("FileNameProvider");
            PluginEntity PECopy;
            if (dPE == null)
            {
                string InstallFile = Path.Combine(Directory.GetCurrentDirectory(), "FileNameProvider.zip");
                bool result = installer.InstallPlugin(InstallFile, false);
                Assert.AreEqual(true, result, "Installation failed");
                dPE = Plugin.GetConfigurationByName("FileNameProvider");
            }
            PECopy = Plugin.GetConfigurationByName("FileNameProvider");

            Assert.AreEqual(true, installer.UninstallPlugin(PECopy), "Uninstall failed");
            Assert.AreEqual(null, Plugin.GetConfigurationByName("FileNameProvider"),
                            string.Format("Plugin: {0} still installed in location: {1}", PECopy.Name, PECopy.Location));
            Assert.AreEqual(false, Directory.Exists(Path.GetDirectoryName(PECopy.Location)),
                            string.Format("Directory {0} still exists", Path.GetDirectoryName(PECopy.Location)));
        }

        private void CheckFiles(PluginEntity pe)
        {
            string dir = Path.GetDirectoryName(pe.Location);
            bool pluginFile = false;
            bool dataFile = false;

            foreach (string file in Directory.GetFiles(dir))
            {
                switch (Path.GetFileName(file))
                {
                    case "FileNameProvider.dll":
                        pluginFile = true;
                        break;

                    case "IMDBTitles.dat":
                        dataFile = true;
                        break;

                    default:
                        Assert.Fail(string.Format("File: {0} should not be in plugin directory", file));
                        break;
                }
            }
            Assert.AreEqual(pluginFile, true, "Plugin file FileNameProvider.dll not in plugin directory");
            Assert.AreEqual(dataFile, true, "data file MovieTitles.dat not in plugin directory");
        }

        [TestMethod]
        [DeploymentItem("IMDBTitles.dat")]        
        public void FileNameProviderTestSingleFileName()
        {
            // For our test files X: is a Media File System
            FileSystemEntity fse = new FileSystemEntity() {directory = "X:", lastScan = null, recurse = true};
            config.FileSystems.Add(fse);
            List<MediaSearchReturn> msr;

            msr =
                provider.SearchForMediaByName(
                    @"X:\E-[DRDO]\Dr. Dolittle 2 [Special Edition].avi");            

            msr =
                provider.SearchForMediaByName(
                    @"X:\Master and Commander x264_LytseBarg\Master and Commander x264.avi");
            
            msr =
                provider.SearchForMediaByName(
                    @"X:\Cars.2006.1080p.BluRay.x264-FLAWL3SS\Cars.avi");
            
            msr =
                provider.SearchForMediaByName(
                    @"X:\Captain.America.The.First.Avenger.2011.720p.BRRip.XviD.AC3-ViSiON\Captain.America.The.First.Avenger.2011.720p.BRRip.XviD.AC3-ViSiON.avi");
            Assert.AreEqual("tt0458339", msr[0].IMDBID);

            msr =
               provider.SearchForMediaByName(
                   @"X:\Bad.Teacher.2011.R5.DVDRip.XVID.AC3-5.1.HQ.Hive-CM8\Bad.Teacher.2011.R5.DVDRip.XVID.AC3-5.1.HQ.Hive-CM8.avi");
            msr =
                provider.SearchForMediaByName(
                    @"X:\I Love You, Beth Cooper (2009)\I Love You, Beth Cooper (2009).AVI");
            
            msr =
                provider.SearchForMediaByName(
                    @"X:\Fringe\Fringe.S01E19.The.Road.Not.Taken.HDTV.XviD-FQM.[VTV].avi");
            Assert.AreEqual("tt1119644", msr[0].IMDBID);

            msr = provider.SearchForMediaByName(
                    @"X:\Blind Guardian, Imaginations Through the Looking Glass (2004)\DVD1 - Imaginations Through The Looking Glass\DVD1 - Imaginations Through The Looking Glass\Title_01_02.avi");
                                    
        }

        [TestMethod]
        [DeploymentItem("TestData.txt")]
        public void FileNameProviderTestAllNames()
        {
            // This runs through all the filenames in TestData.txt and generates a percentage score that tehy are in the top 5
            FileSystemEntity fse = new FileSystemEntity() { directory = "X:", lastScan = null, recurse = true };
            config.FileSystems.Add(fse);
            fse = new FileSystemEntity() { directory = "Y:", lastScan = null, recurse = true };
            config.FileSystems.Add(fse);
            
            StreamReader sr=new StreamReader("TestData.txt");
            string line = string.Empty;
            int iterations = 0;
            int score = 0;
            var scores = new Dictionary<string, int>();
            while ((line = sr.ReadLine()) != null)
            {
                string[] items = line.Split('\t');
                int tmdbID = 0;
                int tvdbID = 0;
                int Season = 0;
                int Episode = 0;
                int currentScore = 0;
                string Filename = string.Empty;
                if (!string.IsNullOrWhiteSpace(items[0]))
                {
                    tvdbID = int.Parse(items[0]);
                }
                if (!string.IsNullOrWhiteSpace(items[1]))
                {
                    tmdbID = int.Parse(items[1]);
                }
                if (!string.IsNullOrWhiteSpace(items[2]))
                {
                    Season = int.Parse(items[2]);
                }
                if (!string.IsNullOrWhiteSpace(items[3]))
                {
                    Episode = int.Parse(items[3]);
                }
                Filename = items[4];

                List<MediaSearchReturn> msr =
                    provider.SearchForMediaByName(Filename);

                if (msr.Count > 0)
                {
                    for (int a = 0; a < msr.Count; a++)
                    {
                        if (tvdbID > 0)
                        {
                            if (msr[a].TVDBID == tvdbID)
                            {
                                if (a < 5)
                                {
                                    currentScore += (5 - a)*15;
                                    if (msr[a].season == Season)
                                    {
                                        currentScore += 10;
                                    }
                                    if (msr[a].episode == Episode)
                                    {
                                        currentScore += 15;
                                    }
                                    break;
                                }
                            }
                        }
                        else
                        {
                            if (tmdbID > 0)
                            {
                                if (msr[a].TMDBID == tmdbID)
                                {
                                    if (a < 5)
                                    {
                                        currentScore += (5 - a)*20;                                        
                                    }
                                    break;
                                }
                            }
                        }
                    }
                }
                score += currentScore;
                scores.Add(Filename,currentScore);
                iterations++;
                System.Threading.Thread.Sleep(1500);
            }

            string resultsString = "Scores: \n";
            foreach (KeyValuePair<string, int> kvp in scores)
            {
                resultsString += string.Format("{0}    {1}\n", kvp.Key, kvp.Value);
            }
            StreamWriter sw = new StreamWriter(string.Format("{0}-{1}-{2} {3}-{4}-{5}.TestResults", System.DateTime.Now.Month, System.DateTime.Now.Day, System.DateTime.Now.Year, System.DateTime.Now.Hour, System.DateTime.Now.Minute, System.DateTime.Now.Second));
            sw.WriteLine(resultsString);
            sw.Close();

            if((score/iterations)<80)
            {                
                Assert.Fail(string.Format("Expected score > 80, got {0}\n{1}",(score/iterations),resultsString));
            }
        }
        
        #endregion Methods

        #region Other

        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //

        #endregion Other
    }
}